// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
#include <pollux/functions/lib/registration_helpers.h>
#include <pollux/functions/prestosql/arithmetic.h>
#include <pollux/functions/prestosql/decimal_functions.h>
#include <pollux/functions/sparksql/arithmetic.h>
#include <pollux/functions/sparksql/decimal_arithmetic.h>
#include <pollux/functions/sparksql/decimal_ceil.h>
#include <pollux/functions/sparksql/rand.h>

namespace kumo::pollux::functions::sparksql {
    void registerMathFunctions(const std::string &prefix) {
        registerUnaryNumeric<AbsFunction>({prefix + "abs"});
        register_function<
            DecimalAbsFunction,
            LongDecimal<P1, S1>,
            LongDecimal<P1, S1> >({prefix + "abs"});
        register_function<
            DecimalAbsFunction,
            ShortDecimal<P1, S1>,
            ShortDecimal<P1, S1> >({prefix + "abs"});
        register_function<AcosFunction, double, double>({prefix + "acos"});
        register_function<AsinFunction, double, double>({prefix + "asin"});
        register_function<AcoshFunction, double, double>({prefix + "acosh"});
        register_function<AsinhFunction, double, double>({prefix + "asinh"});
        register_function<AtanFunction, double, double>({prefix + "atan"});
        register_function<AtanhFunction, double, double>({prefix + "atanh"});
        register_function<SecFunction, double, double>({prefix + "sec"});
        register_function<CscFunction, double, double>({prefix + "csc"});
        register_function<SinhFunction, double, double>({prefix + "sinh"});
        register_function<CosFunction, double, double>({prefix + "cos"});
        register_function<CoshFunction, double, double>({prefix + "cosh"});
        register_function<CotFunction, double, double>({prefix + "cot"});
        register_function<DegreesFunction, double, double>({prefix + "degrees"});
        register_function<Atan2Function, double, double, double>({prefix + "atan2"});
        register_function<Log1pFunction, double, double>({prefix + "log1p"});
        register_function<ToBinaryStringFunction, Varchar, int64_t>({prefix + "bin"});
        register_function<ToHexBigintFunction, Varchar, int64_t>({prefix + "hex"});
        register_function<ToHexVarcharFunction, Varchar, Varchar>({prefix + "hex"});
        register_function<ToHexVarbinaryFunction, Varchar, Varbinary>(
            {prefix + "hex"});
        register_function<ExpFunction, double, double>({prefix + "exp"});
        register_function<Expm1Function, double, double>({prefix + "expm1"});
        registerBinaryIntegral<PModIntFunction>({prefix + "pmod"});
        registerBinaryFloatingPoint<PModFloatFunction>({prefix + "pmod"});
        register_function<PowerFunction, double, double, double>({prefix + "power"});
        register_function<RIntFunction, double, double>({prefix + "rint"});
        registerUnaryNumeric<RoundFunction>({prefix + "round"});
        register_function<RoundFunction, int8_t, int8_t, int32_t>({prefix + "round"});
        register_function<RoundFunction, int16_t, int16_t, int32_t>(
            {prefix + "round"});
        register_function<RoundFunction, int32_t, int32_t, int32_t>(
            {prefix + "round"});
        register_function<RoundFunction, int64_t, int64_t, int32_t>(
            {prefix + "round"});
        register_function<RoundFunction, double, double, int32_t>({prefix + "round"});
        register_function<RoundFunction, float, float, int32_t>({prefix + "round"});
        register_function<UnHexFunction, Varbinary, Varchar>({prefix + "unhex"});
        // In Spark only long, double, and decimal have ceil/floor
        register_function<sparksql::CeilFunction, int64_t, int64_t>({prefix + "ceil"});
        register_function<sparksql::CeilFunction, int64_t, double>({prefix + "ceil"});
        registerDecimalCeil(prefix);
        register_function<sparksql::FloorFunction, int64_t, int64_t>(
            {prefix + "floor"});
        register_function<sparksql::FloorFunction, int64_t, double>(
            {prefix + "floor"});
        registerDecimalFloor(prefix);
        register_function<HypotFunction, double, double, double>({prefix + "hypot"});
        register_function<sparksql::Log2Function, double, double>({prefix + "log2"});
        register_function<sparksql::Log10Function, double, double>({prefix + "log10"});
        register_function<sparksql::LogarithmFunction, double, double, double>(
            {prefix + "log"});
        register_function<
            WidthBucketFunction,
            int64_t,
            double,
            double,
            double,
            int64_t>({prefix + "width_bucket"});
        register_function<RandFunction, double>({prefix + "rand", prefix + "random"});
        register_function<RandFunction, double, Constant<int32_t> >(
            {prefix + "rand", prefix + "random"});
        register_function<RandFunction, double, Constant<int64_t> >(
            {prefix + "rand", prefix + "random"});
        register_function<SignFunction, double, double>({prefix + "sign"});

        // Operators.
        registerBinaryNumeric<PlusFunction>({prefix + "add"});
        registerBinaryNumeric<MinusFunction>({prefix + "subtract"});
        registerBinaryNumeric<MultiplyFunction>({prefix + "multiply"});
        register_function<DivideFunction, double, double, double>({prefix + "divide"});
        registerBinaryNumeric<RemainderFunction>({prefix + "remainder"});
        registerUnaryNumeric<UnaryMinusFunction>({prefix + "unaryminus"});
        register_function<
            UnaryMinusFunction,
            LongDecimal<P1, S1>,
            LongDecimal<P1, S1> >({prefix + "unaryminus"});
        register_function<
            UnaryMinusFunction,
            ShortDecimal<P1, S1>,
            ShortDecimal<P1, S1> >({prefix + "unaryminus"});

        registerDecimalAdd(prefix);
        registerDecimalSubtract(prefix);
        registerDecimalMultiply(prefix);
        registerDecimalDivide(prefix);
        register_function<sparksql::IsNanFunction, bool, float>({prefix + "isnan"});
        register_function<sparksql::IsNanFunction, bool, double>({prefix + "isnan"});

        registerBinaryNumeric<CheckedAddFunction>({prefix + "checked_add"});
        registerBinaryNumeric<CheckedSubtractFunction>({prefix + "checked_subtract"});
        registerBinaryNumeric<CheckedMultiplyFunction>({prefix + "checked_multiply"});
        registerBinaryNumeric<CheckedDivideFunction>({prefix + "checked_divide"});
    }
} // namespace kumo::pollux::functions::sparksql
